package ru.susu.algebra.centralunits.alternating.tex.local;

import java.math.BigInteger;

import ru.susu.algebra.centralunits.alternating.MathMethodWithInitializers;
import ru.susu.algebra.centralunits.alternating.initializers.BetaInitializer;
import ru.susu.algebra.centralunits.alternating.initializers.QuadraticFieldsInitializer;
import ru.susu.algebra.centralunits.alternating.initializers.SpecialRowsInitializer;
import ru.susu.algebra.field.quadratic.QuadraticField;
import ru.susu.algebra.field.quadratic.QuadraticFieldGeneralForm;
import ru.susu.algebra.field.quadratic.QuadraticInteger;
import ru.susu.algebra.jtex.ITexElement;
import ru.susu.algebra.jtex.StringTexElement;
import ru.susu.algebra.jtex.TexBeginEndElement;
import ru.susu.algebra.jtex.UnionTexElement;
import ru.susu.algebra.jtex.formula.GreekSymbols;
import ru.susu.algebra.jtex.formula.MathSymbols;
import ru.susu.algebra.jtex.utils.TexUtils;
import ru.susu.algebra.partition.Partition;
import ru.susu.algebra.properties.IPropertySource;
import ru.susu.algebra.util.NumberUtilities;

/**
 * @author akargapolov
 * @since: 07.09.2010
 */
public class LemmaAboutTracesGenerator extends MathMethodWithInitializers<ITexElement>
{
	private static final Class[] DEPENDENCIES = {SpecialRowsInitializer.class, QuadraticFieldsInitializer.class, BetaInitializer.class};

	@Override
	protected ITexElement directRun(IPropertySource ps) throws Exception
	{
		UnionTexElement union = new UnionTexElement();

		for (Partition partition : SpecialRowsInitializer.listSpecialNotIntegerCharacterRows(ps))
		{
			union.addSubElement(getLemma(partition, ps));
		}

		return union;
	}

	private static String alphaM1 = GreekSymbols.ALPHA + " - 1";
	private static String alphaM1Brackets = TexUtils.inBrackets(alphaM1);

	private String omegaWIndex;
	private QuadraticFieldGeneralForm omega;
	private QuadraticFieldGeneralForm conjugateOmega;
	private QuadraticFieldGeneralForm omega2;

	private ITexElement getLemma(Partition partition, IPropertySource ps) throws Exception
	{
		Integer rowNumber = SpecialRowsInitializer.getRowNumber(ps, partition);
		QuadraticField field = QuadraticFieldsInitializer.getRow2Field(ps).get(partition);
		QuadraticInteger generateInteger = field.getGenerateInteger();
		QuadraticInteger character1 = QuadraticFieldsInitializer.getCharacter(ps, partition);
		QuadraticInteger character2 = character1.getConjugateNumber();
		String aNumber = "A" + TexUtils.index(rowNumber);
		String doubleSlash = "," + MathSymbols.DOUBLE_INV_SLASH + "\n";
		BigInteger sqrtNumber = field.getGenerateInteger().getD();
		omegaWIndex = GreekSymbols.OMEGA + TexUtils.index(sqrtNumber);
		omega = QuadraticFieldsInitializer.getOmega(ps, partition);
		conjugateOmega = (QuadraticFieldGeneralForm)omega.getConjugateNumber();
		omega2 = (QuadraticFieldGeneralForm)omega.pow(BigInteger.valueOf(2));
		String lambdaM1Brackets = TexUtils.inBrackets(GreekSymbols.LAMBDA + " - 1");
		BigInteger beta1 = BetaInitializer.getBetaCoefficient(ps, partition, character1);
		BigInteger beta2 = BetaInitializer.getBetaCoefficient(ps, partition, character2);



		/*Пусть $\lambda=\alpha+\beta\omega_{13}$. Тогда
		\begin{align}
		\tr(\lambda-1)&=2(\alpha-1)+\beta,\\
		\tr(\texttt{*A}(\lambda-1))&=(\alpha-1)-6\beta,\\
		\tr(\texttt{A}(\lambda-1))&=(\alpha-1)+7\beta.
		\end{align}*/

		TexBeginEndElement lemma = TexBeginEndElement.lemma();
		lemma.addSubElement(StringTexElement.text(
				"Пусть $" + GreekSymbols.LAMBDA + " = " + GreekSymbols.ALPHA + " + " + GreekSymbols.BETA + omegaWIndex + "$. Тогда\n"))
				.addSubElement(	TexBeginEndElement.align().addSubElement(StringTexElement.text(
				MathSymbols.TR + lambdaM1Brackets + " &= 2" + alphaM1Brackets + " + " + GreekSymbols.BETA + doubleSlash +
				MathSymbols.TR + TexUtils.inBrackets(aNumber + lambdaM1Brackets) + " &= " + alphaM1Brackets + NumberUtilities.toString(beta1, true, false) + GreekSymbols.BETA + doubleSlash +
				MathSymbols.TR + TexUtils.inBrackets("*" + aNumber + lambdaM1Brackets) + " &= " + alphaM1Brackets + NumberUtilities.toString(beta2, true, false) + GreekSymbols.BETA + ".")));
/*
		\begin{proof}
		В самом деле
		\begin{align*}
		\tr(\lambda-1)=\tr((\alpha-1)+\beta\omega_{13})=2(\alpha-1)+\beta,\\
		\tr(\texttt{*A}(\lambda-1))=\tr((1-\omega_{13})\cdot(\alpha+\beta\omega_{13}-1)=
		\tr((-\beta\omega_{13})^2+(-\alpha+\beta+1)\omega_{13}+(1-\alpha))=\\
		=-7\beta+(\beta-\alpha+1)+2(\alpha-1)=(\alpha-1)-6\beta,\\
		\tr(\texttt{A}(\lambda-1))=\tr(\omega_{13}(\alpha-1+\beta\omega_{13}))=
		\tr((\alpha-1)\omega_{13}+\beta\omega_{13}^2)=\\
		=\tr((\alpha-1)\omega_{13}+(3+\omega_{13})\beta)=\tr((\alpha+\beta-1)\omega_{13}+3\beta)=
		(\alpha+\beta-1)+6\beta=(\alpha-1)+7\beta.
		\end{align*}
		\end{proof}*/

		TexBeginEndElement proof = TexBeginEndElement.proof();
		proof.addSubElement(StringTexElement.text("В самом деле\n")).addSubElement(TexBeginEndElement.align().setWithoutNumber().addSubElement(StringTexElement.text(
				MathSymbols.TR + lambdaM1Brackets + " = " + MathSymbols.TR + MathSymbols.LEFT_BRACKET + alphaM1Brackets + GreekSymbols.BETA + omegaWIndex + MathSymbols.RIGHT_BRACKET +
				" = 2" + alphaM1Brackets + GreekSymbols.BETA + doubleSlash +
				MathSymbols.TR + TexUtils.inBrackets(aNumber + lambdaM1Brackets) + " = " + getProof(character1, beta1) + doubleSlash +
				MathSymbols.TR + TexUtils.inBrackets("*" + aNumber + lambdaM1Brackets) + " = " + getProof(character2, beta2) + ".")));

		return new UnionTexElement().addSubElement(lemma).addSubElement(proof).addSubElement(StringTexElement.newLine());
	}

	private String getProof(QuadraticInteger character, BigInteger beta) throws Exception
	{
		String aTT = character.getA().equals(BigInteger.ZERO) ? "" : NumberUtilities.toString(character.getA(), true, false) + GreekSymbols.BETA;
		String aTF = NumberUtilities.toString(character.getA(), true, false);
		String bFF = NumberUtilities.toString(character.getB(), false, false);
		String bFT = NumberUtilities.toString(character.getB(), false, true);
		String bInvTT = NumberUtilities.toString(character.getB().multiply(BigInteger.valueOf(-1)), true, true);
		String omega2FT = NumberUtilities.toString(omega2.getTrace(), false, true);

		if (!character.getA().multiply(BigInteger.valueOf(2)).add(character.getB()).equals(BigInteger.ONE))
		{
			throw new RuntimeException("Coefficient before alpha - 1 not equals one");
		}

		StringBuffer buffer = new StringBuffer();
		buffer.append("\n" + MathSymbols.TR + TexUtils.inBrackets(TexUtils.inBrackets(TexUtils.toTexString(character)) +
				MathSymbols.CDOT + TexUtils.inBrackets(GreekSymbols.ALPHA + " - 1 + " + GreekSymbols.BETA + omegaWIndex))+
				" = " + MathSymbols.DOUBLE_INV_SLASH + "\n");

		String plusBeforeOmega = " + " + TexUtils.inBrackets(bFF + GreekSymbols.ALPHA + bInvTT + aTT);
		String atfPart = character.getA().equals(BigInteger.ZERO) ? "" : aTF + alphaM1Brackets;
		String atfPart2 = atfPart.length() == 0 ? "" :
			NumberUtilities.toString(character.getA().multiply(BigInteger.valueOf(2)), true, false) + MathSymbols.CDOT + alphaM1Brackets;

		buffer.append(" = " + MathSymbols.TR + TexUtils.inBrackets(bFF + GreekSymbols.BETA + omegaWIndex + TexUtils.pow("2") +
				plusBeforeOmega + omegaWIndex + atfPart) + " = " +  MathSymbols.DOUBLE_INV_SLASH + "\n");

		buffer.append(" = " + bFT + MathSymbols.CDOT + omega2FT + GreekSymbols.BETA + plusBeforeOmega + atfPart2 + " = ");

		buffer.append(alphaM1Brackets + NumberUtilities.toString(beta, true, false) + GreekSymbols.BETA);

		return buffer.toString();
	}

	@Override
	protected Class[] getDependentInitializers()
	{
		return DEPENDENCIES;
	}

}
